package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"stacks/database"
	"stacks/models"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// AuditMiddleware 审计日志中间件
func AuditMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()

		// 复制请求体以便后续读取
		var bodyBytes []byte
		if c.Request.Body != nil {
			bodyBytes, _ = io.ReadAll(c.Request.Body)
			c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
		}

		// 继续处理请求
		c.Next()

		// 记录审计日志
		go recordAuditLog(c, bodyBytes, start)
	}
}

// recordAuditLog 记录审计日志
func recordAuditLog(c *gin.Context, bodyBytes []byte, start time.Time) {
	// 获取用户信息
	userID, username, tenantID := GetUserInfo(c)
	if userID == 0 {
		// 未登录用户不记录审计日志
		return
	}

	// 解析请求体
	var requestBody map[string]interface{}
	if len(bodyBytes) > 0 {
		err := json.Unmarshal(bodyBytes, &requestBody)
		if err != nil {
			return
		}
	}

	// 构建审计日志
	auditLog := models.SysAuditLog{
		UserID:    userID,
		Username:  username,
		TenantID:  tenantID,
		Action:    getAction(c),
		Resource:  getResource(c),
		IP:        c.ClientIP(),
		UserAgent: c.Request.UserAgent(),
	}

	// 设置资源ID
	if resourceID := getResourceID(c); resourceID > 0 {
		auditLog.ResourceID = resourceID
	}

	// 设置操作详情
	auditLog.Details = buildAuditDetails(c, requestBody, start)

	// 保存到数据库
	database.GetDB().Create(&auditLog)
}

// getAction 获取操作类型
func getAction(c *gin.Context) string {
	method := c.Request.Method
	switch method {
	case "GET":
		return "查询"
	case "POST":
		return "创建"
	case "PUT", "PATCH":
		return "更新"
	case "DELETE":
		return "删除"
	default:
		return method
	}
}

// getResource 获取资源类型
func getResource(c *gin.Context) string {
	path := c.Request.URL.Path
	parts := strings.Split(path, "/")

	// 从路径中提取资源类型
	for i, part := range parts {
		if part == "api" && i+1 < len(parts) {
			return parts[i+1]
		}
	}

	return "unknown"
}

// getResourceID 获取资源ID
func getResourceID(c *gin.Context) uint {
	id := c.Param("id")
	if id != "" {
		if idUint, err := parseUint(id); err == nil {
			return idUint
		}
	}
	return 0
}

// buildAuditDetails 构建审计详情
func buildAuditDetails(c *gin.Context, requestBody map[string]interface{}, start time.Time) string {
	details := map[string]interface{}{
		"method":   c.Request.Method,
		"path":     c.Request.URL.Path,
		"query":    c.Request.URL.RawQuery,
		"duration": time.Since(start).String(),
		"status":   c.Writer.Status(),
	}

	// 添加请求体（敏感信息需要过滤）
	if len(requestBody) > 0 {
		filteredBody := filterSensitiveData(requestBody)
		details["request"] = filteredBody
	}

	detailsJSON, _ := json.Marshal(details)
	return string(detailsJSON)
}

// filterSensitiveData 过滤敏感数据
func filterSensitiveData(data map[string]interface{}) map[string]interface{} {
	filtered := make(map[string]interface{})

	sensitiveFields := []string{"password", "token", "secret", "key"}

	for key, value := range data {
		for _, sensitive := range sensitiveFields {
			if strings.Contains(strings.ToLower(key), sensitive) {
				value = "***FILTERED***"
				break
			}
		}
		filtered[key] = value
	}

	return filtered
}

// parseUint 解析字符串为uint
func parseUint(s string) (uint, error) {
	var result uint
	_, err := fmt.Sscanf(s, "%d", &result)
	return result, err
}
